Documentation (Development)
The goal is to offer a similar set of functionality as pexpect.
Basic usage
Add this to your Cargo.toml
[dependencies]
rexpect = "0.3"
Simple example for interacting via ftp:
extern crate rexpect;
use rexpect::spawn;
use rexpect::errors::*;
fn do_ftp() -> Result<()> {
let mut p = spawn("ftp speedtest.tele2.net", Some(30_000))?;
p.exp_regex("Name \\(.*\\):")?;
p.send_line("anonymous")?;
p.exp_string("Password")?;
p.send_line("test")?;
p.exp_string("ftp>")?;
p.send_line("cd upload")?;
p.exp_string("successfully changed.\r\nftp>")?;
p.send_line("pwd")?;
p.exp_regex("[0-9]+ \"/upload\"")?;
p.send_line("exit")?;
p.exp_eof()?;
Ok(())
}
fn main() {
do_ftp().unwrap_or_else(|e| panic!("ftp job failed with {}", e));
}
Example with bash and reading from programs
extern crate rexpect;
use rexpect::spawn_bash;
use rexpect::errors::*;
fn foo() -> Result<()> {
let mut p = spawn_bash(Some(2000))?;
p.send_line("hostname")?;
let hostname = p.read_line()?;
p.wait_for_prompt()?; println!("Current hostname: {}", hostname);
p.send_line("wc /etc/passwd")?;
let (_, lines) = p.exp_regex("[0-9]+")?;
let (_, words) = p.exp_regex("[0-9]+")?;
let (_, bytes) = p.exp_regex("[0-9]+")?;
p.wait_for_prompt()?; println!("/etc/passwd has {} lines, {} words, {} chars", lines, words, bytes);
p.execute("ping 8.8.8.8", "bytes of data")?; for _ in 0..5 {
let (_, duration) = p.exp_regex("[0-9. ]+ ms")?;
println!("Roundtrip time: {}", duration);
}
p.send_control('c')?;
}
Example with bash and job control
One frequent bitfall with sending ctrl-c and friends is that you need
to somehow ensure that the program has fully loaded, otherwise the ctrl-*
goes into nirvana. There are two functions to ensure that:
execute
where you need to provide a match string which is present
on stdout/stderr when the program is ready
wait_for_prompt
which waits until the prompt is shown again
extern crate rexpect;
use rexpect::spawn_bash;
use rexpect::errors::*;
fn run() -> Result<()> {
let mut p = spawn_bash(Some(1000))?;
p.execute("ping 8.8.8.8", "bytes of data")?;
p.send_control('z')?;
p.wait_for_prompt()?;
p.execute("bg", "ping 8.8.8.8")?;
p.wait_for_prompt()?;
p.send_line("sleep 1")?;
p.wait_for_prompt()?;
p.execute("fg", "ping 8.8.8.8")?;
p.send_control('c')?;
p.exp_string("packet loss")?;
Ok(())
}
Project Status
Rexpect covers more or less the features of pexpect. If you miss anything
I'm happy to receive PRs or also Issue requests of course.
The tests cover most of the aspects and it should run out of the box for
rust stable, beta and nightly on both Linux or Mac.
That said, I don't know of too many people using it yet, so use this
with caution.
Design decisions
- use error handling of error-chain
- use nix (and avoid libc wherever possible) to keep the code safe and clean
- sadly,
expect
is used in rust too prominently to unwrap Option
s and Result
s, use exp_*
instead